package com.ht.WeNas.utils;

import cn.hutool.core.util.StrUtil;
import com.ht.WeNas.common.Range;
import com.ht.WeNas.data.dto.FileObj;
import com.ht.WeNas.utils.exceptions.MessageException;
import jakarta.annotation.Nullable;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Optional;

public class RequestFileUtil {
    /**
     * 直接返回文件
     *
     * @param fileObj  文件对象
     * @param response 响应对象
     */
    public static void returnFile(FileObj fileObj, HttpServletResponse response) {
        if (fileObj.isDir()) {
            throw new MessageException("文件无法读取");
        }
        response.setHeader("Content-Length", String.valueOf(fileObj.getSize()));
        response.setHeader("Accept-Ranges", "bytes");
        response.addHeader("Content-Type", fileObj.getContentType());
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType(fileObj.getContentType());
        try (
                FileInputStream is = new FileInputStream(fileObj.getPath())
        ) {
            ServletOutputStream os = response.getOutputStream();
            int n;
            byte[] cache = new byte[8 * 1024];
            while ((n = is.read(cache)) != -1) {
                os.write(cache, 0, n);
                os.flush();
            }
        } catch (IOException ignore) {
        }
    }

    /**
     * 根据范围返回部分文件
     *
     * @param fileObj  文件对象
     * @param response 响应对象
     * @param range    范围对象
     * @param size     指定的大小，为空则返回全部
     */
    public static void returnFileRange(FileObj fileObj, HttpServletResponse response, Range range, @Nullable Long size) {
        if (fileObj.isDir()) {
            throw new MessageException("文件无法读取");
        }
        if (range == null) {
            throw new IllegalArgumentException();
        }
        response.addHeader("Accept-Ranges", "bytes");
        response.addHeader("Content-Type", fileObj.getContentType());
        long total = fileObj.getSize();
        long start = Optional.ofNullable(range.getStart()).orElse(0L);
        long end = Optional.ofNullable(range.getEnd()).orElse(total - 1);
        if (size != null) {
            end = start + size;
        }
        if (end > total - 1) {
            end = total - 1;
        }
        response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + total);
        response.addHeader("Content-Length", String.valueOf(end - start + 1));
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        try (
                RandomAccessFile reader = new RandomAccessFile(fileObj.getPath(), "r");
                ServletOutputStream os = response.getOutputStream()
        ) {
            reader.seek(start);
            byte[] cache = new byte[8 * 1024];
            int n;
            while ((n = reader.read(cache)) != -1) {
                os.write(cache, 0, n);
                os.flush();
            }
        } catch (IOException ignore) {
        }
    }

    /**
     * 获取请求范围
     *
     * @param request 请求对象
     * @return 请求范围对象，如果没有请求范围或解析失败，则返回null
     */
    public static Range getRange(HttpServletRequest request) {
        String range = request.getHeader("Range");
        if (StrUtil.isBlank(range)) {
            return null;
        }
        return Range.getInstance(range);
    }
}
